package nl.renedegroot.android.intervalbeeper;

import java.util.Timer;

import nl.renedegroot.android.intervalbeeper.widget.NumberPicker;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.ToggleButton;

public class BeeperActivity extends ListActivity
{

   private static final String KEEPAWAKE = "keepawake";
   private final OnClickListener mStartOnClickListener = new OnClickListener()
      {
         public void onClick(View v)
         {
            long minutesItem = mMinutesSpinner.getSelectedItemId();
            int minutes = 60 * 1000 * BeeperActivity.this.getResources().getIntArray(R.array.minutes_intervals_values)[(int) minutesItem];
            long secondsItem = mSecondsSpinner.getSelectedItemId();
            int seconds = 1000 * BeeperActivity.this.getResources().getIntArray(R.array.seconds_intervals_values)[(int) secondsItem];

            long soundsItem = mSoundsSpinner.getSelectedItemId();

            addSingleTimer(minutes + seconds, (int) soundsItem);
         }
      };
   private final OnClickListener mStopOnClickListener = new OnClickListener()
      {
         public void onClick(View v)
         {
            removeAllTimers();
         }
      };

   private View.OnClickListener mPlayPauseListener = new View.OnClickListener()
      {
         public void onClick(View v)
         {
            doPlayStop();
         }
      };
   private DialogInterface.OnClickListener mOiAboutDialogListener = new DialogInterface.OnClickListener()
      {
         public void onClick(DialogInterface dialog, int which)
         {
            Uri oiDownload = Uri.parse("market://details?id=org.openintents.about");
            Intent oiAboutIntent = new Intent(Intent.ACTION_VIEW, oiDownload);
            try
            {
               startActivity(oiAboutIntent);
            }
            catch (ActivityNotFoundException e)
            {
               oiDownload = Uri.parse("http://openintents.googlecode.com/files/AboutApp-1.0.0.apk");
               oiAboutIntent = new Intent(Intent.ACTION_VIEW, oiDownload);
               startActivity(oiAboutIntent);
            }
         }
      };
   private DialogInterface.OnClickListener mPeriodDialogListener = new DialogInterface.OnClickListener()
      {
         public void onClick(DialogInterface dialog, int which)
         {
            int period = 1000 * (mDialogPeriodMinutes.getValue() * 60 + mDialogPeriodSeconds.getValue());
            mDialogSound.setPeriod(period);
            mIntervalAdapter.update();
         }
      };
   private DialogInterface.OnClickListener mDelayDialogListener = new DialogInterface.OnClickListener()
      {
         public void onClick(DialogInterface dialog, int which)
         {
            int delay = 1000 * (mDialogDelayMinutes.getValue() * 60 + mDialogDelaySeconds.getValue());
            mDialogSound.setDelay(delay);
            mIntervalAdapter.update();
         }
      };
   private OnSeekBarChangeListener mOnSeekBarChangeListener = new OnSeekBarChangeListener()
      {

         public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
         {
            if (fromUser)
            {
               int max = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
               int index = (max * progress) / 100;
               mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, index + 1, AudioManager.FLAG_SHOW_UI);
            }
         }

         public void onStartTrackingTouch(SeekBar seekBar)
         {
            // NOOP
         }

         public void onStopTrackingTouch(SeekBar seekBar)
         {
            // NOOP
         }
      };
   private OnCheckedChangeListener mAwakeListener = new OnCheckedChangeListener()
      {
         @Override
         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
         {
            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(BeeperActivity.this);
            Editor edit = prefs.edit();
            edit.putBoolean(KEEPAWAKE, isChecked);
            edit.commit();
            if( !isChecked && mWakeLock.isHeld() )
            {
               mWakeLock.release();
            }
            if( isChecked && mIntervalAdapter.isPlaying() )
            {
               mWakeLock.acquire();
            }
         }
      };

   private NumberPicker mDialogPeriodMinutes;
   private NumberPicker mDialogPeriodSeconds;
   private NumberPicker mDialogDelayMinutes;
   private NumberPicker mDialogDelaySeconds;
   private Spinner mMinutesSpinner;
   private Spinner mSecondsSpinner;
   private ImageButton mAddButton;
   private ImageButton mDelButton;
   private ImageButton mPlayPauseButton;
   private Spinner mSoundsSpinner;
   private SeekBar mVolumeSlider;
   private ToggleButton mAwakeToggle;
   
   private AudioManager mAudioManager;
   private SoundTimer mDialogSound;
   private SoundsAdapter mSoundsAdapter;
   private IntervalAdapter mIntervalAdapter;
   private WakeLock mWakeLock;
   private static Timer sTimer = new Timer();

   private static final int MENU_ITEM_ABOUT = Menu.FIRST;
   private static final int MENU_ITEM_CUSTOMS = Menu.FIRST + 1;
   private static final int DIALOG_INSTALL_ABOUT = Menu.FIRST + 2;
   private static final int MENU_DELAY = Menu.FIRST + 3;
   private static final int MENU_PERIOD = Menu.FIRST + 4;
   private static final int DIALOG_DELAY = Menu.FIRST + 5;
   private static final int DIALOG_PERIOD = Menu.FIRST + 6;

   private static final String TAG = "BeeperActivity";

   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState)
   {
//      Log.d(TAG, "onCreate()");
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);

      // Add the context menu (the long press thing)
      registerForContextMenu(getListView());
      
      mAwakeToggle = (ToggleButton) findViewById(R.id.awakeToggle);
      mAwakeToggle.setOnCheckedChangeListener(mAwakeListener);
      mAddButton = (ImageButton) findViewById(R.id.beeper_btn_add);
      mAddButton.setOnClickListener(this.mStartOnClickListener);
      mDelButton = (ImageButton) findViewById(R.id.beeper_btn_clear);
      mDelButton.setOnClickListener(this.mStopOnClickListener);
      mPlayPauseButton = (ImageButton) findViewById(R.id.btn_playpause);
      mPlayPauseButton.setOnClickListener(mPlayPauseListener);
      mVolumeSlider = (SeekBar) findViewById(R.id.volume_slider);
      mVolumeSlider.setOnSeekBarChangeListener(mOnSeekBarChangeListener);
      mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
      int vol = (mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC) * 100) / mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
      mVolumeSlider.setProgress(vol);

      mMinutesSpinner = (Spinner) findViewById(R.id.minutes_interval);
      ArrayAdapter<CharSequence> minutesAdapter = ArrayAdapter.createFromResource(this, R.array.minutes_intervals, android.R.layout.simple_spinner_item);
      minutesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
      mMinutesSpinner.setAdapter(minutesAdapter);

      mSecondsSpinner = (Spinner) findViewById(R.id.seconds_interval);
      ArrayAdapter<CharSequence> secondsAdapter = ArrayAdapter.createFromResource(this, R.array.seconds_intervals, android.R.layout.simple_spinner_item);
      secondsAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
      mSecondsSpinner.setAdapter(secondsAdapter);

      mSoundsSpinner = (Spinner) findViewById(R.id.sounds_names);
      mSoundsAdapter = new SoundsAdapter(this);
      mSoundsSpinner.setAdapter(mSoundsAdapter);
      
      Object prevState = getLastNonConfigurationInstance();
      if (prevState != null)
      {
         Object[] objects = (Object[]) prevState;
//         Log.d(TAG, "LastNonConfigurationInstance()");
         mIntervalAdapter = (IntervalAdapter) objects[0];
         mDialogSound = (SoundTimer) objects[1];
         mWakeLock = (WakeLock) objects[2];
      }
      else
      {
//         Log.d(TAG, "new IntervalCursor()");
         mIntervalAdapter = new IntervalAdapter(this);
         PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, TAG);
      }
      
      boolean lock = false;
      lock = PreferenceManager.getDefaultSharedPreferences(this).getBoolean(KEEPAWAKE, lock);
      mAwakeToggle.setChecked(lock);
     
      setListAdapter(mIntervalAdapter);

      setPauseButtonImage();
   }

   @Override
   protected void onResume()
   {
      super.onResume();
      boolean isChecked = PreferenceManager.getDefaultSharedPreferences(this).getBoolean(KEEPAWAKE, false);
      if( isChecked && mIntervalAdapter.isPlaying() )
      {
         mWakeLock.acquire();
      }
   }
   
   @Override
   protected void onPause()
   {
      super.onPause();
      if( mWakeLock.isHeld() )
      {
         mWakeLock.release();
      }
   }
   
   /*
    * (non-Javadoc)
    * @see android.app.Activity#onDestroy()
    */
   @Override
   protected void onDestroy()
   {
//      Log.d(TAG, "onDestroy()");
      super.onDestroy();
      setListAdapter(null);
      if (isFinishing())
      {
         removeAllTimers();
      }
   }

   @Override
   public Object onRetainNonConfigurationInstance()
   {
//      Log.d(TAG, "onRetainNonConfigurationInstance()");
      return new Object[]{ mIntervalAdapter, mDialogSound, mWakeLock };
   }

   private synchronized void addSingleTimer(long period, int sound)
   {

      if (period > 0)
      {
         final SoundTimer timerTask = mSoundsAdapter.createSoundTimer(sound, period);
         mIntervalAdapter.add(timerTask);
         if (mIntervalAdapter.isPlaying())
         {
            timerTask.setTimer(sTimer);
         }
      }
      else
      {
         final SoundTimer timerTask = mSoundsAdapter.createSoundTimer(sound);
         mIntervalAdapter.add(timerTask);
         if (mIntervalAdapter.isPlaying())
         {
            timerTask.setTimer(sTimer);
         }
      }
   }

   private synchronized void doPlayStop()
   {
      if (mIntervalAdapter.isPlaying())
      {
         if( mWakeLock.isHeld() )
         {
            mWakeLock.release();
         }
         mIntervalAdapter.resetAll();
      }
      else
      {
         boolean lock = PreferenceManager.getDefaultSharedPreferences(this).getBoolean(KEEPAWAKE, false);
         if( lock )
         {
            mWakeLock.acquire();
         }
         mIntervalAdapter.startAll(sTimer);
      }
      setPauseButtonImage();
   }

   private synchronized void removeAllTimers()
   {
//      Log.d(TAG, "removeAllTimers()");
      if( mWakeLock.isHeld() )
      {
         mWakeLock.release();
      }
      mIntervalAdapter.removeAll();
      setPauseButtonImage();
   }

   private void setPauseButtonImage()
   {
      if (mIntervalAdapter.isPlaying())
      {
         mPlayPauseButton.setImageResource(R.drawable.ic_media_stop);
      }
      else
      {
         mPlayPauseButton.setImageResource(android.R.drawable.ic_media_play);
      }
   }

   /*
    * (non-Javadoc)
    * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
    */
   @Override
   public boolean onCreateOptionsMenu(Menu menu)
   {
      super.onCreateOptionsMenu(menu);

      menu.add(ContextMenu.NONE, MENU_ITEM_CUSTOMS, ContextMenu.NONE, R.string.menu_customs).setIcon(android.R.drawable.ic_menu_preferences);
      //About action
      menu.add(ContextMenu.NONE, MENU_ITEM_ABOUT, ContextMenu.NONE, R.string.menu_about).setIcon(android.R.drawable.ic_menu_info_details);
      return true;
   }

   /*
    * (non-Javadoc)
    * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
    */
   @Override
   public boolean onOptionsItemSelected(MenuItem item)
   {
      switch (item.getItemId())
      {
         case MENU_ITEM_ABOUT:
            // Show the about dialog for this app.
            startAboutActivity();
            return true;
         case MENU_ITEM_CUSTOMS:
            // Show the about dialog for this app.
            startCustomSoundsActivity();
            return true;
         default:
            // Whoops, unknown menu item.
            Log.e(TAG, "Unknown menu item");
      }
      return super.onOptionsItemSelected(item);
   }

   @Override
   protected void onListItemClick(ListView l, View v, int position, long id)
   {
      super.onListItemClick(l, v, position, id);
      mIntervalAdapter.removeOne(position);
   }

   @Override
   public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)
   {
      if (menuInfo instanceof AdapterView.AdapterContextMenuInfo)
      {
         AdapterView.AdapterContextMenuInfo itemInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
         TextView textView = (TextView) itemInfo.targetView.findViewById(android.R.id.text1);
         if (textView != null)
         {
            menu.setHeaderTitle(textView.getText());
         }
      }
      menu.add(0, MENU_DELAY, 0, R.string.menu_delay);
      menu.add(0, MENU_PERIOD, 0, R.string.menu_period);
   }

   @Override
   public boolean onContextItemSelected(MenuItem item)
   {
      boolean handled = false;
      AdapterView.AdapterContextMenuInfo info;
      try
      {
         info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
      }
      catch (ClassCastException e)
      {
         Log.e(TAG, "Bad menuInfo", e);
         return handled;
      }

      mDialogSound = (SoundTimer) getListAdapter().getItem(info.position);
      switch (item.getItemId())
      {
         case MENU_DELAY:
         {
            showDialog(DIALOG_DELAY);
            handled = true;
            break;
         }
         case MENU_PERIOD:
         {
            showDialog(DIALOG_PERIOD);
            handled = true;
            break;
         }
         default:
            handled = super.onContextItemSelected(item);
            break;
      }
      return handled;
   }

   /*
    * (non-Javadoc)
    * @see android.app.Activity#onCreateDialog(int)
    */
   @Override
   protected Dialog onCreateDialog(int id)
   {
      Dialog dialog = null;
      Builder builder = null;
      View view = null;
      LayoutInflater factory = LayoutInflater.from( this );
      
      switch (id)
      {
         case DIALOG_INSTALL_ABOUT:
            builder = new AlertDialog.Builder(this);
            builder.setTitle(R.string.dialog_nooiabout)
               .setMessage(R.string.dialog_nooiabout_message)
               .setIcon(android.R.drawable.ic_dialog_alert)
               .setPositiveButton(R.string.btn_install, mOiAboutDialogListener)
               .setNegativeButton(R.string.btn_cancel, null);
            dialog = builder.create();
            return dialog;
         case DIALOG_DELAY:
            view = factory.inflate( R.layout.period_spinner, null );
            mDialogDelayMinutes = (NumberPicker) view.findViewById(R.id.minutes);
            mDialogDelaySeconds = (NumberPicker) view.findViewById(R.id.seconds);
            builder = new AlertDialog.Builder(this);
            builder.setTitle(R.string.menu_delay)
               .setPositiveButton(R.string.btn_okay, mDelayDialogListener)
               .setNegativeButton(R.string.btn_cancel, null)
               .setView(view);
            dialog = builder.create();
            return dialog;
         case DIALOG_PERIOD:
            view = factory.inflate( R.layout.period_spinner, null );
            mDialogPeriodMinutes = (NumberPicker) view.findViewById(R.id.minutes);
            mDialogPeriodSeconds = (NumberPicker) view.findViewById(R.id.seconds);
            builder = new AlertDialog.Builder(this);
            builder.setTitle(R.string.menu_period)
               .setPositiveButton(R.string.btn_okay, mPeriodDialogListener)
               .setNegativeButton(R.string.btn_cancel, null)
               .setView(view);
            dialog = builder.create();
            return dialog;
         default:
            return super.onCreateDialog(id);
      }
   }
   
   @Override
   protected void onPrepareDialog(int id, Dialog dialog)
   {
      switch (id)
      {
         case DIALOG_DELAY:
            long delayMinutes = mDialogSound.getDelay() / 1000 / 60;
            long delaySeconds = mDialogSound.getDelay() / 1000 % 60;
            mDialogDelayMinutes.changeCurrent((int) delayMinutes);
            mDialogDelaySeconds.changeCurrent((int) delaySeconds);
            break;
         case DIALOG_PERIOD:
            long periodMinutes = mDialogSound.getPeriod() / 1000 / 60;
            long periodSeconds = mDialogSound.getPeriod() / 1000 % 60;
            mDialogPeriodMinutes.changeCurrent((int) periodMinutes);
            mDialogPeriodSeconds.changeCurrent((int) periodSeconds);
            break;
         default:
            super.onPrepareDialog(id, dialog);
            break;
      }
   }

   private void startCustomSoundsActivity()
   {
      Intent intent = new Intent(this, RegisterSoundActivity.class);
      startActivity(intent);
   }

   /**
    * Show an about dialog for this application.
    */
   protected void startAboutActivity()
   {

   }

}